/*
 * Funambol is a mobile platform developed by Funambol, Inc. 
 * Copyright (C) 2008 Funambol, Inc.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission 
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE 
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Affero General Public License 
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 * 
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite 
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 * 
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 * 
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably 
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include "TimeUtils.h"
#include "Date.h"

/**
 * The name of the timezone should follow the Olson ID that can be undestood by the 
 * NSTimeZone object
 */
bool checkValidTimezone(const char* t) {
    // timezone is right name because it is using the info stored in the db
    bool ret = true;
    
    if (t == NULL || strcmp(t, "") == 0) {
        return false;
    }
    
    NSString* timezone = [[NSString alloc] initWithUTF8String:t];
    NSTimeZone* tz = [NSTimeZone timeZoneWithName:timezone];
    
    if (tz) {
        LOG.debug("The timezone found is %s", t);
        ret = true;
        goto finally;
    }
    
    if (tz == NULL) {
        LOG.debug("The timezone %s is not found: try with abbreviation method ", t);
        tz = [NSTimeZone timeZoneWithAbbreviation:timezone];
    }
    
    if (tz == NULL) {
        LOG.error("It is not possible to find the timezone: %s", t);
        ret = false;
    }
    
finally:
    [timezone release];
    [tz release];
    
    return ret;
}

/**
 * It fills the value according to have 2 digits
 */
StringBuffer getFilledValue(int val) {
    char v[8];
    sprintf(v, "%02d", val);
    StringBuffer ret(v);
    return ret;
}

/**
 * It returns the current timezone on the device
 */
StringBuffer getCurrentTimezone() {
    NSTimeZone* tz = [NSTimeZone systemTimeZone];
    NSString* tzname = [tz name];
    const char* c = [tzname UTF8String];
    StringBuffer ret(c);
    
    return ret;
}

NSTimeZone* getNSTimezone(const Timezone& tzone) {
    
    const char* t = tzone.getName();
    NSString* timezone = [[NSString alloc] initWithUTF8String:t];
    NSTimeZone* tz = [NSTimeZone timeZoneWithName:timezone]; 
    [timezone release];
    return tz;
    
}
/**
 * It returns a NSTimeZone object according to the timezone in the date. If date.getDate() contains
 * a Z the NSTimeZone returned is a GMT timezone. If not, the timezone is retrieved by the ones set in the Date.getTimezone()
 * 
 */
NSTimeZone* getNSTimezone(Date& date) {
    NSTimeZone* tz;
    if(strstr(date.getDate(), "Z") != 0) {
        tz = [NSTimeZone timeZoneWithName:@"GMT"];
    } else {
        tz = getNSTimezone(date.getTimezone());
    }
    return tz;
}


/**
 * Internal method only used for the conversion of the date with the timezone
 */
NSDate* getAppleDateValueForTimezone(NSTimeZone* tz, const char* date) {
    
    int y = 1970, m = 01, d = 01;
    int h = -1, mm = 00, ss = 00;
    sscanf(date, "%04d%02d%02dT%02d%02d%02d", &y, &m, &d, &h, &mm, &ss);
    
    NSDateComponents *comps = [[NSDateComponents alloc] init]; 
    [comps setYear:y];
    [comps setMonth:m];
    [comps setDay:d];
    [comps setHour:h];
    [comps setMinute:mm];
    [comps setSecond:ss];
    
    NSCalendar *gregorian = [[NSCalendar alloc]                             
                             initWithCalendarIdentifier:NSGregorianCalendar];
    
    [gregorian setTimeZone:tz];        
    NSDate *nsdate = [gregorian dateFromComponents:comps];
    
    [comps release];
    return nsdate;
    
}

/**
 * Internal method only used to get the string date in format yyyymmddThhmmss
 * with the hour that is calculated properly with the value of the offset
 */
StringBuffer getStringDateForTimezone(NSTimeZone* tz, NSDate* cdate, long offset) {
    
    
    NSCalendar* gregorian = [NSCalendar currentCalendar];
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit |
                         NSMinuteCalendarUnit | NSSecondCalendarUnit;
    
    StringBuffer ret;
    [gregorian setTimeZone:tz];
    
    NSDateComponents *comps = [gregorian components:unitFlags fromDate:cdate];
    NSInteger year = [comps year];
    NSInteger month = [comps month];
    NSInteger day = [comps day];
    NSInteger h = [comps hour];
    NSInteger m = [comps minute];
    NSInteger s = [comps second];
    h = h + (offset / 3600);
    ret.append(getFilledValue(year));
    ret.append(getFilledValue(month));
    ret.append(getFilledValue(day));   
    ret.append("T"); 
    ret.append(getFilledValue(h));
    ret.append(getFilledValue(m));
    ret.append(getFilledValue(s));       
    
    return ret;
}

/**
 * It returns a NSDate that is the representation of when the next rule changes.
 * It means that if the date is 2008-01-01 Europe/Rome the next change rule is on 2008-03-29 at 3 AM
 */
NSDate* getRuleChange(NSTimeZone* tz, NSDate* date) {
    
    // add 60 sec to be sure to doesn't get a date that doesn't move the next transition
    NSDate* nextTransition = [date addTimeInterval:60]; 
    NSDate* ret = [tz nextDaylightSavingTimeTransitionAfterDate:nextTransition];
    [nextTransition release];
    return ret;
}

bool getTimezoneInfo(long year, const char* t, StringBuffer& standardDate, StringBuffer& daylightDate, 
                     long* standardOffset, long* daylightOffset, long* onlyOffset) {

    
    // timezone is right name because it is using the info stored in the db
    StringBuffer timez;
    if (t == NULL || strcmp(t, "") == 0) {
        timez = "GMT";
    } else {
        timez = t;
    }
    NSString* timezone = [[NSString alloc] initWithUTF8String:timez.c_str()];
    NSTimeZone* tz = [NSTimeZone timeZoneWithName:timezone];
    
    if (tz == NULL) {
        tz = [NSTimeZone timeZoneWithAbbreviation:timezone];
    }
    
    if (tz == NULL) {
        LOG.error("It is not possible to find the timezone: %s", timez.c_str());
        return false;
    }
    
    StringBuffer stdDate; stdDate.sprintf("%i0702T120000", year); // actually the date is in daylight if exists. used to get the next standard
    StringBuffer dlsDate; dlsDate.sprintf("%i0102T120000", year); // actually the date is in standard if exists. used to get the next daylight
    
    NSDate* std = getAppleDateValueForTimezone(tz, stdDate.c_str());
    NSDate* dls = getAppleDateValueForTimezone(tz, dlsDate.c_str());
    
    NSDate* s = getRuleChange(tz, std); 
    NSDate* d = getRuleChange(tz, dls);
    
    NSTimeInterval lstd = [s timeIntervalSinceReferenceDate];    
    NSTimeInterval ldls = [d timeIntervalSinceReferenceDate];    
    
    if (lstd == 0 && ldls == 0) { // it means there is no daylight 
        NSTimeInterval onOffset     = [tz secondsFromGMT];
        *onlyOffset = -(long)onOffset / 60; 
        *standardOffset = 0;
        *daylightOffset = 0;
    }
    else { 
        
        // to get the standard date offset use the dls date, that is the date retrieved when
        // the daylight date is not yet started
        NSTimeInterval stdOffset    = [tz secondsFromGMTForDate:dls];  
        NSTimeInterval dlOffset     = [tz secondsFromGMTForDate:std];
        
        standardDate = getStringDateForTimezone(tz, s, dlOffset-stdOffset);
        daylightDate = getStringDateForTimezone(tz, d, -(dlOffset-stdOffset));    
    
        *standardOffset = -(long)stdOffset / 60;
        *daylightOffset = -(long)dlOffset / 60;
    }
    
    [s release];
    [d release];
    [std release];
    [dls release];
    [timezone release];
    [tz release];
    
    return true;
}

/**
 * Used the same convention used for windows plugin for the day of week mask
 * iphone uses 1=sun, 2=mon, 3=tue, 4=wed, 5=thu, 6=fri, 7=sat
 * windows is  1=sun, 2=mon, 4=tue, 8=wed, 16=thu, 32=fri, 64=sat
 */

long convertDayofWeekFromAppleToStandard(long day) {
    if (day == 3) 
        return 4;
    if (day == 4)
        return 8;
    if (day == 5)
        return 16;
    if (day == 6)
        return 32;
    if (day == 7)
        return 64;
    return day;
}
/**
 * As before it convert form the conventional value to the one apple wants
 * iphone uses 1=sun, 2=mon, 3=tue, 4=wed, 5=thu, 6=fri, 7=sat
 * windows is  1=sun, 2=mon, 4=tue, 8=wed, 16=thu, 32=fri, 64=sat
 */ 
long convertDayofWeekFromStandardToApple(long day) {
    if (day == 4) 
        return 3;
    if (day == 8)
        return 4;
    if (day == 16)
        return 5;
    if (day == 32)
        return 6;
    if (day == 64)
        return 7;
    return day;
}



/**
 * Get the day of the week from a date (usually to be supposed the date is in local time)
 * the value returned is 1 for sunday, 2 for monday 3 for wednesday...
 */
long getDayOfWeekFromStandardDate(Date& value) {
    long date = getAppleDateValueFromStandard(value);
    return getValueFromAppleDate(date, 0);
}

long getDayOfMonthFromStandardDate(Date& value) {
    long date = getAppleDateValueFromStandard(value);
    return getValueFromAppleDate(date, 1);
}


/**
 * Get the day of the week from a date (usually to be supposed the date is in local time)
 * the value returned is 1 for sunday, 2 for monday 3 for wednesday...
 */
long getDayOfWeekFromAppleDate(long value) {
    return getValueFromAppleDate(value, 0);
}

/**
 * Get the day of the month from a date (usually to be supposed the date is in local time)
 * the returned values are 1,2,3....
 */
long getDayOfMonthFromAppleDate(long value) {
    return getValueFromAppleDate(value, 1);
}

/**
 * Get the month of the year from a date (usually to be supposed the date is in local time)
 * a month of year (1=JAN, 2=FEB, 3=MAR)
 */
long getMonthOfYearFromAppleDate(long value) {
    return getValueFromAppleDate(value, 2);
}

long getYearFromAppleDate(long value) {
    return getValueFromAppleDate(value, 3);
}

long getAppleDateValueFromStandard(Date& date) {
    NSDate* nsdate = getAppleDateValue(date);
    NSTimeInterval time = [nsdate timeIntervalSinceReferenceDate];
    [nsdate release];
    return time;
}

/**
 * Get the week day from a date (usually to be supposed the date is in local time
 * Due to select value, the returned could be 
 * - select = 0: a day of week (1=SUN, 2=MON, 3=TUE...)  
 * - select = 1: a day of month (19, 15...)
 * - select = 2: a month of year (1=JAN, 2=FEB, 3=MAR)
 * - select = 3: the year (2008, 2009...)
 * The function is called using the other two useful method
 */
long getValueFromAppleDate(long value, int select) {
    
    long ret = -1;
    NSDate *cdate = [NSDate dateWithTimeIntervalSinceReferenceDate:value]; // reference date since 01-01-1970
    
    NSCalendar* gregorian = [NSCalendar currentCalendar];
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit |
                         NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekdayCalendarUnit | NSWeekdayOrdinalCalendarUnit;
    
    NSDateComponents *comps = [gregorian components:unitFlags fromDate:cdate];
    
    // NSInteger hour = [comps hour];
    // NSInteger min = [comps minute];
    // NSInteger sec = [comps second];
    // NSInteger weekordinalr = [comps weekdayOrdinal];
    
    NSInteger day       = [comps day];
    NSInteger weekday   = [comps weekday];
    NSInteger month     = [comps month];
    NSInteger year      = [comps year];
    
    if (select == 0) { // day of week
        ret = weekday;
    }
    else if (select == 1) { // day of month
        ret = day;
    }
    else if (select == 2) {
        ret = month;
    }
    else if (select == 3) {
        ret = year;
    } 
    
    [cdate release];
    [comps release];
    return ret;
}

StringBuffer convertAppleDateToStandard(const char* d, bool isAllDay, bool convertUTC) {
    
    long value = 0; 
    if (d) {
        value = atol(d);
    }
    return convertAppleDateToStandard(value, isAllDay, convertUTC);
}

/**
 * Functions that are has to be shared with the objective-c language. 
 * Used to convert the date from the db into the string of the event.
 * The values are computed referring to the 2001-01-01 date. Date before that date
 * are negative. Date before the 19321213T21455 are considered as the default 19010101 (-2147483648)
 * Tested function... 
 */
StringBuffer convertAppleDateToStandard(long value, bool isAllDay, bool convertUTC) {
    
    NSDate *cdate = [NSDate dateWithTimeIntervalSinceReferenceDate:value]; // reference date since 01-01-1970
    
    NSCalendar* gregorian = [NSCalendar currentCalendar];
    NSTimeZone *tzutc = [NSTimeZone timeZoneWithName:@"GMT"]; // the timezone for the UTC
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit |
    NSMinuteCalendarUnit | NSSecondCalendarUnit;
    
    StringBuffer ret;
    
    if (isAllDay) {
        NSDateComponents *comps = [gregorian components:unitFlags fromDate:cdate];
        NSInteger year = [comps year];
        NSInteger month = [comps month];
        NSInteger day = [comps day];
        ret.append(getFilledValue(year));
        ret.append(getFilledValue(month));
        ret.append(getFilledValue(day));        
    } else {
        // set the timezone of London to see the conversion in UTC. Otherwise keep the local one
        if (convertUTC) {
            [gregorian setTimeZone:tzutc];
        }
        NSDateComponents *comps = [gregorian components:unitFlags fromDate:cdate];
        NSInteger year = [comps year];
        NSInteger month = [comps month];
        NSInteger day = [comps day];
        NSInteger h = [comps hour];
        NSInteger m = [comps minute];
        NSInteger s = [comps second];
        ret.append(getFilledValue(year));
        ret.append(getFilledValue(month));
        ret.append(getFilledValue(day));   
        ret.append("T"); 
        ret.append(getFilledValue(h));
        ret.append(getFilledValue(m));
        ret.append(getFilledValue(s));       
        if (convertUTC) {
            ret.append("Z");
        }
    }
    return ret;
    
}

NSDate* getMidnightDate(NSDate* date, Timezone& tz, bool utc) {
    NSDate* nsdate = calculateBorderDay(date, tz, 0, utc);
    return nsdate;
}

NSDate* getEndOfTheDay(NSDate* date, Timezone& tz, bool utc) {
    NSDate* nsdate = calculateBorderDay(date, tz, 23, utc);
    return nsdate;
}

NSDate* calculateBorderDay(NSDate* date, Timezone& tz, int when, bool utc) {
    
    NSCalendar* gregorian = [[NSCalendar alloc]                             
                             initWithCalendarIdentifier:NSGregorianCalendar];        
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit |
                         NSMinuteCalendarUnit | NSSecondCalendarUnit;
    
    NSDateComponents *comps = [gregorian components:unitFlags fromDate:date];
    if (when == 0) {
        [comps setHour:0];
        [comps setMinute:0];
        [comps setSecond:0];
    } else if (when == 23) {
        [comps setHour:23];
        [comps setMinute:59];
        [comps setSecond:59];
    }
    if (utc) {
        [gregorian setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
    } else {
        [gregorian setTimeZone:getNSTimezone(tz)];
    }
    NSDate* nsdate = [gregorian dateFromComponents:comps];
    [comps release];
    return nsdate;
    
}

/**
 * Get local apple date at midnight. Used to calculate the day in the recurrence
 */
long getLocalMidnightAppleDate(long value, Timezone& tz) {
    
    NSDate *nsdate = [NSDate dateWithTimeIntervalSinceReferenceDate:value];
    NSDate *newDate = getMidnightDate(nsdate, tz);
    NSTimeInterval time = [newDate timeIntervalSinceReferenceDate];
    [nsdate release];
    [newDate release];
    return time;
}

/**
 * The date that must be used at the end of the Recurrence. Given the start date of the recurrence
 * it calculate the end of the same day.
 * I.E. given a value 2132344 that is 20080829T150000 it must be calculate
 * the value returned must be 20080829T235959 in GMT +0.
 */
long getDateEndRecurrence(long endDayRec, Timezone& tz) {
    
    NSDate *nsdate = [NSDate dateWithTimeIntervalSinceReferenceDate:endDayRec];
    NSDate *newDate = getEndOfTheDay(nsdate, tz, true);
    NSTimeInterval time = [newDate timeIntervalSinceReferenceDate];
    [nsdate release];
    [newDate release];
    return time;
    
}

/**
 * It needs to add a numberOfYear year to the existing one retrieved
 * by the current date
 */
long addYearToAppleDate(long day, int numberOfYear) {
    
    long year = getYearFromAppleDate(day);
    NSDate *nsdate = [NSDate dateWithTimeIntervalSinceReferenceDate:day];
    NSCalendar* gregorian = [[NSCalendar alloc]                             
                             initWithCalendarIdentifier:NSGregorianCalendar];        
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit |
                         NSMinuteCalendarUnit | NSSecondCalendarUnit;
    
    NSDateComponents *comps = [gregorian components:unitFlags fromDate:nsdate];
    year += numberOfYear;
    [comps setYear:year];
    [nsdate release];
    
    nsdate = [gregorian dateFromComponents:comps];
    NSTimeInterval time = [nsdate timeIntervalSinceReferenceDate];
    [nsdate release];
    [comps release];
    return time;
    
}

/**
 * It returns the number of unit (days, month, years) given a startdate, end date and a type
 * 0 means the result is a number of days
 * 1 means the result is a number of months
 * 2 means the result is a number of years
 */
long getNumberOfUnitByDates(long startdate, long enddate, int type, Timezone& tz) {
    
    NSDate *startDate = [NSDate dateWithTimeIntervalSinceReferenceDate:startdate];
    NSDate *endDate = [NSDate dateWithTimeIntervalSinceReferenceDate:enddate];
    
    NSCalendar* gregorian = [[NSCalendar alloc]                             
                             initWithCalendarIdentifier:NSGregorianCalendar];     
    
    NSTimeZone* tzone = getNSTimezone(tz);
    [gregorian setTimeZone:tzone];
    
    unsigned int unitFlags = 0; 
    int value = 0; 
    
    if (type == 0) {
        unitFlags = NSDayCalendarUnit;
    } else if (type == 1) {
        unitFlags = NSMonthCalendarUnit;
    } else if (type == 2) {
        unitFlags = NSYearCalendarUnit;
    }
    
    NSDateComponents *comps = [gregorian components:unitFlags fromDate:startDate  toDate:endDate  options:0];
    
    
    if (type == 0) {
        value = [comps day];
    } else if (type == 1) {
        value = [comps month];
    } else if (type == 2) {
        value = [comps year];
    }
    
    [startDate release];
    [endDate release];
    [comps release];
    return value;
}

/**
 * It calculate the number of days since 2 dates, specified by 2 long...
 */
long getNumberOfDaysByDates(long startdate, long enddate, Timezone& tz) {
    return getNumberOfUnitByDates(startdate, enddate, 0, tz);    
}

long getNumberOfMonthsByDates(long startdate, long enddate, Timezone& tz) {
    return getNumberOfUnitByDates(startdate, enddate, 1, tz); 
}

long addComponentsToDate(long date, Timezone& tz, int days, int months, int years) {
    
    NSDate *nsdate = [NSDate dateWithTimeIntervalSinceReferenceDate:date];
    NSCalendar* gregorian = [[NSCalendar alloc]                             
                             initWithCalendarIdentifier:NSGregorianCalendar];        
    NSDateComponents *adding = [[NSDateComponents alloc] init];
    
    if (days != 0) {
        [adding setDay:days];
    }
    if (months != 0) {
        [adding setMonth:months];
    }
    if (years != 0) {
        [adding setYear:years];
    }
    NSTimeZone* tzone = getNSTimezone(tz);
    
    [gregorian setTimeZone:tzone];
    
    NSDate *newdate = [gregorian dateByAddingComponents:adding toDate:nsdate  options:0];
    
    NSTimeInterval time = [newdate timeIntervalSinceReferenceDate];
    
    [nsdate release];
    [adding release];
    [newdate release];
    
    return time;  
}

/**
 * Return the new date in long format that has days added. 
 * Used to calculate the number of occurrences
 */
long addDaysToDate(long date, Timezone& tz, int days) {
    return addComponentsToDate(date, tz, days, 0, 0);
}

long addMonthsToDate(long date, Timezone& tz, int months) {
    return addComponentsToDate(date, tz, 0, months, 0);
}

long addYearsToDate(long date, Timezone& tz, int years) {
    return addComponentsToDate(date, tz, 0, 0, years);
}

/**
 * Functions that are has to be shared with the objective-c language. 
 * Used to convert the date from the string format YYYYMMDD server into the date number of the db.
 * It takes care of the Timezone
 */
StringBuffer convertStandardToAppleDate(Date& date, bool localMidnight) {
    
    NSDate* nsdate = getAppleDateValue(date);
    Timezone& tz = (Timezone&)date.getTimezone();
    StringBuffer ret;
    
    if (localMidnight) {
        NSDate *newDate = getMidnightDate(nsdate, tz);
        [nsdate release];
        nsdate = newDate;
    }
    
    NSTimeInterval time = [nsdate timeIntervalSinceReferenceDate];
    
    long temp = (long)time;
    char t[256]; 
    sprintf(t, "%i", temp);
    ret.append(t);
    LOG.debug("Value of date at the end **** %s", ret.c_str());    
    
    StringBuffer converted = convertAppleDateToStandard(ret.c_str(), false, false);
    LOG.debug("date converted %s", converted.c_str());
    
    [nsdate release];
    
    return ret;
    
}



void normalizeForAllDay(Date& dtmp, bool allDay) {
    if (allDay == false) {
        return;
    }
    
    const char* date = dtmp.getDate();
    int y = 1970, m = 01, d = 01;
    int h = -1, mm = 00, ss = 00;
    LOG.debug("The date is: %s", date);
    if (strlen(date) > 8) {        
        sscanf(date, "%04d%02d%02dT%02d%02d%02d", &y, &m, &d, &h, &mm, &ss);
    } else {
        sscanf(date, "%04d%02d%02d", &y, &m, &d);
    }
    
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit |
    NSMinuteCalendarUnit | NSSecondCalendarUnit;
    
    NSDateComponents *comps = [[NSDateComponents alloc] init]; 
    [comps setYear:y];
    [comps setMonth:m];
    [comps setDay:d];
    if (h > -1) {
        [comps setHour:h];
        [comps setMinute:mm];
        [comps setSecond:ss];
    } else {
        h = 0; // set to 0 even if not strictl necessary...
    }
    
    NSCalendar *gregorian = [[NSCalendar alloc]                             
                             initWithCalendarIdentifier:NSGregorianCalendar];
    
    NSTimeZone *tzutc = [NSTimeZone timeZoneWithName:@"GMT"]; // the timezone for the UTC
    //NSString *zoneName = [tzutc name];
    //StringBuffer pp = [zoneName cStringUsingEncoding:NSASCIIStringEncoding];
    //LOG.debug("Name of the timezone %s", pp.c_str());
    
    if(strstr(date, "Z") != 0) {
        [gregorian setTimeZone:tzutc];        
    }
    
    NSDate *nsdate = [gregorian dateFromComponents:comps];  
    
    // add one minute if the hour and minutes are 23:59
    if (h == 23 && mm == 59) {
        NSDate *nn = [nsdate addTimeInterval:60];
        
        [gregorian release];
        [comps release];
        
        gregorian = [[NSCalendar alloc]                             
                     initWithCalendarIdentifier:NSGregorianCalendar];
        
        comps = [gregorian components:unitFlags fromDate:nn];
        
        StringBuffer ret;
        NSInteger year =  [comps year];
        NSInteger month = [comps month];
        NSInteger day =   [comps day];
        NSInteger hour =    [comps hour];
        NSInteger min = [comps minute];
        NSInteger sec = [comps second];
        ret.append(getFilledValue(year));
        ret.append(getFilledValue(month));
        ret.append(getFilledValue(day));   
        ret.append("T"); 
        ret.append(getFilledValue(hour));
        ret.append(getFilledValue(min));
        ret.append(getFilledValue(sec));       
        
        LOG.debug("Date converted normalizeForAllDay %s", ret.c_str());
        dtmp.setDate(ret.c_str());
        [nn release];
    }
    
    [comps release];
    [nsdate release];
    [gregorian release];
    [tzutc release];
    
    return;
    
}


/**
 * Given a string formatted as YYYYmmddTHHmmssZ or YYYYmmddTHHmmss it return a long value
 * since the 01-01-1970. The caller must free the NSDate object
 */
NSDate* getAppleDateValue(Date& date) {
    
    LOG.debug("*** getAppleDateValue: Value of date %s. Value of timezone is %s", date.getDate(), date.getTimezone().getName());
    StringBuffer ret;
    if (date.getDate() == "") {
        LOG.error("convertStandardToAppleDate failed. value is NULL");
        return 0;
    }
    
    int y = 1970, m = 01, d = 01;
    int h = -1, mm = 00, ss = 00;
    LOG.debug("The date is: %s", date.getDate());
    if (strlen(date.getDate()) > 8) {        
        sscanf(date.getDate(), "%04d%02d%02dT%02d%02d%02d", &y, &m, &d, &h, &mm, &ss);
    } else {
        sscanf(date.getDate(), "%04d%02d%02d", &y, &m, &d);
    }
    NSDateComponents *comps = [[NSDateComponents alloc] init]; 
    [comps setYear:y];
    [comps setMonth:m];
    [comps setDay:d];
    if (h > -1) {
        [comps setHour:h];
        [comps setMinute:mm];
        [comps setSecond:ss];
    } else {
        h = 0; // set to 0 even if not strictl necessary...
    }
    
    NSCalendar *gregorian = [[NSCalendar alloc]                             
                             initWithCalendarIdentifier:NSGregorianCalendar];
    
    NSTimeZone* tz = getNSTimezone(date);
    [gregorian setTimeZone:tz];        
    
    NSDate *nsdate = [gregorian dateFromComponents:comps];
    
    [comps release];
    [tz release];
    
    return nsdate;
    
}

int getNumberOfMonthDays(long month, long year) {
    
    int days = 31;
    
    switch (month) {
            
        case 2: {
            if (((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
                days = 29;
            else
                days = 28;
            break;
        }
        case 4:
        case 6:
        case 9:
        case 11:
            days = 30;
            break;
        default:
            break;
            
    }
    return days;
}

NSDateComponents* getDateComponentsFromDate1970(long date){
    NSDate* nsdate = [NSDate dateWithTimeIntervalSince1970:date];
    NSCalendar* gregorian = [[NSCalendar alloc]                             
                             initWithCalendarIdentifier:NSGregorianCalendar];        
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit |
    NSMinuteCalendarUnit | NSSecondCalendarUnit;
    
    NSDateComponents *comps = [gregorian components:unitFlags fromDate:nsdate];
    return comps;
}


